#include "include/HqHttpHead.hpp"

#include <string>
#include <cstring>
#include <iostream>
#include <map>
#include <memory>
using namespace std;


#include "include/tools.h"
using namespace std;

// 请求头
// string method ;
// string path ;
// string version ;
// map<string, string> headers;
// map<string, string> path_params; // 路径上的参数
// unique_ptr<char[]> body; // 字节流

// 构造函数，即完成解包动作
HqHttpHead::HqHttpHead(char *buf, int len)
{
    int p = 0, q = 0; // 开始和结束
    for (int i = 0; i < len; i++)
    {
        if (buf[i] == ' ')
        { // 按照空格分割
            q = i;
            this->method = string(buf + p, buf + q); // [p,q)
            p = q + 1;
            break;
        }
    }
    for (int i = p; i < len; i++)
    {
        if (buf[i] == ' ')  // “/getname?key=val ”
        {
            q = i;
            char *pchar = buf + p; // 指向开头    
            while(  pchar != buf + q ){
                if( *pchar == '?' ){
                    this->path = string(buf + p, pchar); //   /getname   
                    this->path_params=splite_the_params(pchar,  (buf + q) );  // ?key=val
                    break;
                }
                printf("%c", *pchar);
                pchar++;
            }
            if( pchar == buf + q )
                this->path = string(buf + p, buf + q);
            p = q + 1;
            break; 
        }
    }
    for (int i = p; i < len; i++)
    {
        if (buf[i] == '\r')
        {
            q = i;
            this->version = string(buf + p, buf + q);
            p = q + 1;
            break;
        }
    }

    // if(!this->path_params.empty()){
    //     printf("\n\nthis->path_params.empty()) \n");
    //     for(auto the_pair : this->path_params)
    //         cout << the_pair.first << " " << the_pair.second << endl;
    //     printf(" this->path_params.empty()) \n");
    // }

    // 解析headers
    string key = "", value = "";
    for (int i = p; i < len;)
    {
        if (buf[i] == ':' && key == "")
        {
            q = i;
            key = string(buf + p, buf + q);
            p = q + 1;
            while (buf[p] == ' ')
            {
                ++p;
            }
            i = p;
        }
        else if (buf[i] == '\r')
        {
            if (key != "")
            {
                q = i;
                value = string(buf + p, buf + q);
                this->headers.insert({key, value}); // 添加到头
                key = "";
                p = q + 2;
                i = p;
            }
            else
            { // 读取完头部
                p = i + 2;
                break;
            }
        }
        else
        {
            ++i;
        }
    }
    // 解析 body
    if (this->method == "GET")
        return;
    int bodyLen = len - p;
    auto it = this->headers.find("Content-Type");
    if (it != this->headers.end())
        bodyLen = std::stoi(it->second);
    if (bodyLen < 1)
        return;
    this->body.reset(new char[bodyLen + 1]);
    memcpy(this->body.get(), buf + p, bodyLen);
}

// 输出函数
ostream &operator<<(ostream &os, const HqHttpHead &h)
{
    os << h.method << " " << h.path << " " << h.version << endl;
    for (auto it : h.headers)
    {
        os << it.first << ": " << it.second << endl;
    }
    if (h.body)
    {
        os << "has body  " << endl;
    }
    else
    {
        os << "no body  " << endl;
    }
    return os;
}
string HqHttpHead::getFirstLine()
{
    string s;
    s = method + " " + path + " " + version;
    return s;
}

//  相应头
// string version;
// int resCode;
// string resDescr;
// map<string, string> headers;
// unique_ptr<char[]> body; //相应体
// MyFileStream *mfs; // 如果不为空，表示body没有数据，是一个文件流
// int ContentLength;

HqHttpResHead::HqHttpResHead()
{
    this->version = "HTTP/1.0";
    this->resCode = 200;
    this->resDescr = "OK";
    this->ContentLength = 0;
    this->headers["Content-Type"] = "text/html;charset=utf-8";
    this->mfs = nullptr;
}
HqHttpResHead::HqHttpResHead(HqHttpResHead &&h)
{
    this->version = h.version;
    this->resCode = h.resCode;
    this->resDescr = h.resDescr;
    this->ContentLength = h.ContentLength;
    this->headers = h.headers;
    this->mfs = h.mfs;
    h.mfs = nullptr;
    this->body = move(h.body);
}

void HqHttpResHead::setCode(int code)
{
    HqHttpResHead();
    this->resCode = code;
    if (code >= 200)
    {
        this->resDescr = "OK";
    }
    else if (code >= 300)
    {
        this->resDescr = "Moved Permanently";
    }
    else if (code >= 400)
    {
        this->resDescr = "Not Found";
    }
}
HqHttpResHead::~HqHttpResHead()
{
    if (!mfs)
        delete mfs;
}

void HqHttpResHead::setBody(char *buf, int bodyLen)
{
    this->body.reset(new char[bodyLen + 1]);
    memcpy(this->body.get(), buf, bodyLen);
    this->ContentLength = bodyLen;
    sprintf(buf, "%d", bodyLen);
    this->headers["Content-Length"] = string(buf);
}
void HqHttpResHead::setType(string type)
{
    this->headers["Content-Type"] = type;
}
void HqHttpResHead::setHeader(string key, string val)
{
    this->headers[key] = val;
}
int HqHttpResHead::getAllData(char *buf)
{
    int offset = 0;
    offset += sprintf(buf + offset, "%s %d %s\r\n",
                      this->version.c_str(),
                      this->resCode,
                      this->resDescr.c_str());
    for (auto it : this->headers)
    {
        offset += sprintf(buf + offset, "%s: %s\r\n",
                          it.first.c_str(),
                          it.second.c_str());
    }
    offset += sprintf(buf + offset, "\r\n");
    if (this->body)
    {
        memcpy(buf + offset, this->body.get(), ContentLength);
        offset += ContentLength;
    }

    return offset;
}
